package 多线程.ThreadLocal类深入学习;

/**
 * @author jing
 * @结论  从这段代码的输出结果可以看出，在main线程中和thread1线程中，longLocal保存的副本值和stringLocal保存的副本值都不一样。
 */
/*
1）为何threadLocals的类型ThreadLocalMap的键值为ThreadLocal对象，因为每个线程中可有多个threadLocal变量，
  就像上面代码中的longLocal和stringLocal；
2）在进行get之前，必须先set，否则会报空指针异常；
  如果想在get之前不需要调用set就能正常访问的话，必须重写initialValue()方法。

常见应用场景：用来解决 数据库连接、Session管理等。
 */
public class ThreadLcoalTest {
    //1、不重写ThreadLocal类中initialValue()方法时，在进行get之前，必须先set，否则会报空指针异常；
//    ThreadLocal<Long> longLocal = new ThreadLocal<Long>();
//    ThreadLocal<String> stringLocal = new ThreadLocal<String>();
     //2、改进版：重写initialValue()方法
    ThreadLocal<Long> longLocal = new ThreadLocal<Long>(){
        @Override
        protected Long initialValue() {
            return Thread.currentThread().getId(); //默认将当前线程的ID初始化为线程副本
        }
    };
    ThreadLocal<String> stringLocal=new ThreadLocal<String>(){
        @Override
        protected String initialValue() {
            return Thread.currentThread().getName(); //默认将当前线程的名字初始化为线程副本
        }
    };

    //手动设置线程副本的属性值
    public void set() {
        longLocal.set(Thread.currentThread().getId());  //线程当前ID
        stringLocal.set(Thread.currentThread().getName()); //线程当前名字
    }

    public long getLong() {
        return longLocal.get();
    }

    public String getString() {
        return stringLocal.get();
    }

    public static void main(String[] args) throws InterruptedException {
        final ThreadLcoalTest test = new ThreadLcoalTest();

        //主线程
        test.set();
        System.out.println("线程ID："+test.getLong());
        System.out.println("线程名字："+test.getString());

        //新线程
        Thread thread1 = new Thread(){
            public void run() {
                test.set();
                System.out.println("线程ID："+test.getLong());
                System.out.println("线程名字："+test.getString());
            };
        };
        Thread thread2 = new Thread(){
            public void run() {
                test.set();
                System.out.println("线程ID："+test.getLong());
                System.out.println("线程名字："+test.getString());
            };
        };
        thread1.start();
        thread2.start();
        thread1.join(); //等待线程结束
        thread2.join(); //等待线程结束

    }
}
